/**********************************************************************************************************************
 * @file    nmea.c
 * @author  Queclink Jason.Huang
 * @date    2018-12-29
 * @brief   NMEA (National Marine Electronics Association) Protocol basic source.
 *
 * Copyright (C) 2018 Queclink Wireless Solutions (ShenZhen) Co., Ltd. All Rights Reserved.
 *
 * @attention
 *
 * @usage
 *
 *********************************************************************************************************************/

/* includes ---------------------------------------------------------------------------------------------------------*/
#include "aadl/aadl.h"
#include "nmea.h"
#include <qlcommon.h>

#include "gnss_log.h"

extern bool nema_output_en;

nmea_protocol_parse_t* get_nmea_manage_context(void)
{
	nmea_protocol_parse_t 	*nmea_s_t = NULL;
	if (NULL == get_gnss_manage())
		return NULL;

	if (NULL == get_gnss_manage()->gnss_priv[0]) {
		nmea_s_t = qlmalloc(sizeof(nmea_protocol_parse_t));
		if (NULL == nmea_s_t)
			return NULL;
		memset (nmea_s_t, 0, sizeof(nmea_protocol_parse_t));
		if (nmea_s_t != NULL) {
			nmea_s_t->stage = STAGE_HEAD;
		}
		get_gnss_manage()->gnss_priv[0] = nmea_s_t;
	}

	return (nmea_protocol_parse_t*)(get_gnss_manage()->gnss_priv[0]);
}

/*
 * @brief  nmea协议消息字符串分割函数
 * @note
 * @param  str: [I], 待分割的消息字符串
 *         separator: [I], 分隔符
 *		   list: [O], 保存分割得到的字符串首地址
 *		   list_len: [I], 保存字符串的最大数量
 * @retval 分割后的字符串数量
 */
int nmea_string_split(unsigned char *str, const char * separator, char *list[], int list_len)
{

	int cnt = 0;
	const char *p;

	if (str == NULL || list == NULL || list_len == 0)
		return 0;
	list[cnt++] = (char*)str;
	while (*str != '\0'){
		p = separator;
		while (*p != '\0'){
			if (*str == *p){
				*str = '\0';              			/*将分隔符替换成结束符*/
				if (cnt >= list_len)
					return cnt;
				list[cnt++] = (char*)str + 1;       /*指向下一个子串*/
			}
			p++;
		}
		str++;
	}
	return cnt;
}

/*
 * @brief  nmea协议消息校验
 * @note
 * @param  buf: [I], 待校验的nmea消息
 * @retval false:校验错误, true:校验成功
 */
bool nmea_check_crc(const unsigned char *buf)
{

	unsigned char checksum = 0;

	buf++;                                        	/*跳过'$'字符*/
	while (*buf != '*'){
		checksum ^= *buf++;
		if (*buf == '\0')
			return 0;
	}
	buf++;                                          /*跳过'*'字符*/
	return (strtoul((char *)buf, NULL, 16) & 0xff) == checksum;
}

static const nmea_parse_handler_t nmea_handler_tbl[] =
{
	"TXT", nmea_txt_parse,
	"RMC", nmea_rmc_parse,
	"GGA", nmea_gga_parse,
	"GSA", nmea_gsa_parse,
	"GSV", nmea_gsv_parse,
	"GST", nmea_gst_parse,
	//"PMTK", nmea_pmtk_parse
};

#define NMEA_NAME(type, name)	name
static const char * const nmea_type_tbl[] = {
	NMEA_NAME(NMEA_TYPE_GGA, "GGA"),
	NMEA_NAME(NMEA_TYPE_GLL, "GLL"),
	NMEA_NAME(NMEA_TYPE_GSA, "GSA"),
	NMEA_NAME(NMEA_TYPE_RMC, "RMC"),
	NMEA_NAME(NMEA_TYPE_GSV, "GSV"),
	NMEA_NAME(NMEA_TYPE_VTG, "VTG"),
};


void gnss_nmea_recv(char *nema_msg)
{
	char type = 0;
	for (;type<=NMEA_TYPE_VTG; type++) {
		if (strstr(nema_msg, nmea_type_tbl[type])) {

        }
	}
}


/*
 * @brief  解析NMEA协议消息
 * @note
 * @param  buf: [I], 数据指针
 * 		   len: [I], 数据长度
 * @retval 0:收到合法的NMEA数据，other: 未接收到nmea信息
 */
int nmea_protocol_parse(unsigned char *buf, int len, void *ext_hdr, int num)
{

	nmea_protocol_parse_t *nmea_ptr;
	int i;
	int ptr_cnt;
	int j;
    int ret = -1;
	nmea_ptr = get_nmea_manage_context();
	if (NULL == nmea_ptr)
		return -ENOMEM;

	nmea_parse_handler_t* ext_handler = ext_hdr;	/* 扩展的指令处理, 非标准的 NMEA 消息 */

	for(i=0;i<len;i++){
		if(buf[i]== '$'){
			nmea_ptr->length = 0;
			nmea_ptr->stage = STAGE_DATA;
			nmea_ptr->buffer[nmea_ptr->length++] = buf[i];
			continue;
		}
		if ((nmea_ptr->length+1) >= sizeof(nmea_ptr->buffer)){
			nmea_ptr->stage= STAGE_HEAD;
			continue;
		}

		if (buf[i] == '\r' || buf[i] == '\n')		/* 忽略\r\n */
			continue;

		nmea_ptr->buffer[nmea_ptr->length++] = buf[i];
		switch(nmea_ptr->stage){
			case STAGE_DATA:
				if(buf[i] == '*'){
					nmea_ptr->stage = STAGE_BCC_H;
				}
			break;
			case STAGE_BCC_H:
				nmea_ptr->stage = STAGE_BCC_L;
				break;
			case STAGE_BCC_L:
				nmea_ptr->buffer[nmea_ptr->length++]='\0';
				if(nmea_check_crc(nmea_ptr->buffer)){
					/* 回调 */
					gnss_nmea_recv((char *)nmea_ptr->buffer);

					ptr_cnt = nmea_string_split(nmea_ptr->buffer,",*",nmea_ptr->ptr_list,sizeof(nmea_ptr->ptr_list)/sizeof(char*));
					if (strstr(nmea_ptr->ptr_list[0], "VTG") != NULL)
						nmea_ptr->has_disable_msg |= VTG_MASK;
					if (strstr(nmea_ptr->ptr_list[0], "GLL") != NULL)
						nmea_ptr->has_disable_msg |= GLL_MASK;

					for (j= 0; j < sizeof(nmea_handler_tbl) / sizeof(nmea_parse_handler_t); j++){
						if (strstr(nmea_ptr->ptr_list[0], nmea_handler_tbl[j].name) != NULL){
                            ret = 0;
							if (nmea_handler_tbl[j].handler != NULL){
								nmea_handler_tbl[j].handler(ptr_cnt, nmea_ptr->ptr_list);
								break;
							}
						}
					}

					if (NULL != ext_handler && 0 < num) {
						for (j=0; j<num; j++) {
							if (0 == strlen(ext_handler[j].name)
								 || strstr(nmea_ptr->ptr_list[0], ext_handler[j].name) != NULL) {
								ret = 0;
								if (ext_handler[j].handler != NULL){
									ext_handler[j].handler(ptr_cnt, nmea_ptr->ptr_list);
									break;
								}
							}
						}
					}
				}else{
                    for (j= 0; j < sizeof(nmea_handler_tbl) / sizeof(nmea_parse_handler_t); j++){
                        if (strstr((const char *)nmea_ptr->buffer, nmea_handler_tbl[j].name) != NULL){
                            gnss_trace(LOG_WARN"NMEA CRC error.\r\n");
                        }
                    }
				}
                nmea_ptr->stage = STAGE_HEAD;
				break;
			default:
				break;
		}
	}
    return ret;
}
